/*
 * Copyright (c) 2022, IMMORTA Inc.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 *
 * - Redistributions of source code must retain the above copyright notice, this list
 *   of conditions and the following disclaimer.
 *
 * - Redistributions in binary form must reproduce the above copyright notice, this
 *   list of conditions and the following disclaimer in the documentation and/or
 *   other materials provided with the distribution.
 *
 * - Neither the name of IMMORTA Inc. nor the names of its
 *   contributors may be used to endorse or promote products derived from this
 *   software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#ifndef CLOCK_REG_ACCESS_H
#define CLOCK_REG_ACCESS_H

/*!
 * @file clock_reg_access.h
 * @brief This file declares or defines clock register access functions
 */

/*******Includes***************************************************************/
#include "device_registers.h"
#include "clock_drv.h"

/*******Definitions************************************************************/
/* Control Register Bit Fields */
#define CLOCK_CR_HSISTOPEN(x)       (((uint32_t)(((uint32_t)(x)) << CLOCK_CR_HSISTOPEN_Pos)) & CLOCK_CR_HSISTOPEN_Msk)
#define CLOCK_CR_SYSCLKSRC(x)       (((uint32_t)(((uint32_t)(x)) << CLOCK_CR_SYSCLKSRC_Pos)) & CLOCK_CR_SYSCLKSRC_Msk)
#define CLOCK_CR_PERI0PVAL(x)       (((uint32_t)(((uint32_t)(x)) << CLOCK_CR_PERI0PVAL_Pos)) & CLOCK_CR_PERI0PVAL_Msk)
#define CLOCK_CR_AHBPVAL(x)         (((uint32_t)(((uint32_t)(x)) << CLOCK_CR_AHBPVAL_Pos)) & CLOCK_CR_AHBPVAL_Msk)
#define CLOCK_CR_PERI1PVAL(x)       (((uint32_t)(((uint32_t)(x)) << CLOCK_CR_PERI1PVAL_Pos)) & CLOCK_CR_PERI1PVAL_Msk)
#define CLOCK_CR_APBPVAL(x)         (((uint32_t)(((uint32_t)(x)) << CLOCK_CR_APBPVAL_Pos)) & CLOCK_CR_APBPVAL_Msk)
#define CLOCK_CR_LOCFS(x)           (((uint32_t)(((uint32_t)(x)) << CLOCK_CR_LOCFS_Pos)) & CLOCK_CR_LOCFS_Msk)
#define CLOCK_CR_LOLFS(x)           (((uint32_t)(((uint32_t)(x)) << CLOCK_CR_LOLFS_Pos)) & CLOCK_CR_LOLFS_Msk)

/* XOSC/HSE Control Register Bit Fields */
#define CLOCK_XOSCCR_EN(x)          (((uint32_t)(((uint32_t)(x)) << CLOCK_XOSCCR_EN_Pos)) & CLOCK_XOSCCR_EN_Msk)
#define CLOCK_XOSCCR_BYPEN(x)       (((uint32_t)(((uint32_t)(x)) << CLOCK_XOSCCR_BYPEN_Pos)) & CLOCK_XOSCCR_BYPEN_Msk)
#define CLOCK_XOSCCR_IBS(x)         (((uint32_t)(((uint32_t)(x)) << CLOCK_XOSCCR_IBS_Pos)) & CLOCK_XOSCCR_IBS_Msk)
#define CLOCK_XOSCCR_MONEN(x)       (((uint32_t)(((uint32_t)(x)) << CLOCK_XOSCCR_MONEN_Pos)) & CLOCK_XOSCCR_MONEN_Msk)

/* PLL Control Register Bit Fields */
#define CLOCK_PLLCR_EN(x)           (((uint32_t)(((uint32_t)(x)) << CLOCK_PLLCR_EN_Pos)) & CLOCK_PLLCR_EN_Msk)
#define CLOCK_PLLCR_REFSEL(x)       (((uint32_t)(((uint32_t)(x)) << CLOCK_PLLCR_REFSEL_Pos)) & CLOCK_PLLCR_REFSEL_Msk)
#define CLOCK_PLLCR_LOCKMONEN(x)    (((uint32_t)(((uint32_t)(x)) << CLOCK_PLLCR_LOCKMONEN_Pos)) & CLOCK_PLLCR_LOCKMONEN_Msk)
#if (CONFIG_CLOCK_NEW_FEATURES == 1U)
#define CLOCK_PLLCR_LOCKEN(x)       (((uint32_t)(((uint32_t)(x)) << CLOCK_PLLCR_LOCKEN_Pos)) & CLOCK_PLLCR_LOCKEN_Msk)
#endif
#define CLOCK_PLLCR_PREDIV(x)       (((uint32_t)(((uint32_t)(x)) << CLOCK_PLLCR_PREDIV_Pos)) & CLOCK_PLLCR_PREDIV_Msk)
#define CLOCK_PLLCR_FBDIV(x)        (((uint32_t)(((uint32_t)(x)) << CLOCK_PLLCR_FBDIV_Pos)) & CLOCK_PLLCR_FBDIV_Msk)
#define CLOCK_PLLCR_POSTDIV1(x)     (((uint32_t)(((uint32_t)(x)) << CLOCK_PLLCR_POSTDIV1_Pos)) & CLOCK_PLLCR_POSTDIV1_Msk)
#define CLOCK_PLLCR_POSTDIV2(x)     (((uint32_t)(((uint32_t)(x)) << CLOCK_PLLCR_POSTDIV2_Pos)) & CLOCK_PLLCR_POSTDIV2_Msk)
#define CLOCK_PLLCR_LFR(x)          (((uint32_t)(((uint32_t)(x)) << CLOCK_PLLCR_LFR_Pos)) & CLOCK_PLLCR_LFR_Msk)
#define CLOCK_PLLCR_ICP(x)          (((uint32_t)(((uint32_t)(x)) << CLOCK_PLLCR_ICP_Pos)) & CLOCK_PLLCR_ICP_Msk)

/* Peripheral Function Clock Selection Register Bit Fields */
#if (CONFIG_CLOCK_NEW_FEATURES == 1U)
#define CLOCK_PFCSR_ADC0CLKSEL(x)   (((uint32_t)(((uint32_t)(x)) << CLOCK_PFCSR_ADC0CLKSEL_Pos)) & CLOCK_PFCSR_ADC0CLKSEL_Msk)
#define CLOCK_PFCSR_ADC1CLKSEL(x)   (((uint32_t)(((uint32_t)(x)) << CLOCK_PFCSR_ADC1CLKSEL_Pos)) & CLOCK_PFCSR_ADC1CLKSEL_Msk)
#define CLOCK_PFCSR_CAN0CLKSEL(x)   (((uint32_t)(((uint32_t)(x)) << CLOCK_PFCSR_CAN0CLKSEL_Pos)) & CLOCK_PFCSR_CAN0CLKSEL_Msk)
#define CLOCK_PFCSR_CAN1CLKSEL(x)   (((uint32_t)(((uint32_t)(x)) << CLOCK_PFCSR_CAN1CLKSEL_Pos)) & CLOCK_PFCSR_CAN1CLKSEL_Msk)
#define CLOCK_PFCSR_CAN2CLKSEL(x)   (((uint32_t)(((uint32_t)(x)) << CLOCK_PFCSR_CAN2CLKSEL_Pos)) & CLOCK_PFCSR_CAN2CLKSEL_Msk)
#define CLOCK_PFCSR_TIMER0CLKSEL(x) (((uint32_t)(((uint32_t)(x)) << CLOCK_PFCSR_TIMER0CLKSEL_Pos)) & CLOCK_PFCSR_TIMER0CLKSEL_Msk)
#define CLOCK_PFCSR_TIMER1CLKSEL(x) (((uint32_t)(((uint32_t)(x)) << CLOCK_PFCSR_TIMER1CLKSEL_Pos)) & CLOCK_PFCSR_TIMER1CLKSEL_Msk)
#define CLOCK_PFCSR_TIMER2CLKSEL(x) (((uint32_t)(((uint32_t)(x)) << CLOCK_PFCSR_TIMER2CLKSEL_Pos)) & CLOCK_PFCSR_TIMER2CLKSEL_Msk)
#define CLOCK_PFCSR_TIMER3CLKSEL(x) (((uint32_t)(((uint32_t)(x)) << CLOCK_PFCSR_TIMER3CLKSEL_Pos)) & CLOCK_PFCSR_TIMER3CLKSEL_Msk)
#define CLOCK_PFCSR_CMP0CLKSEL(x)   (((uint32_t)(((uint32_t)(x)) << CLOCK_PFCSR_CMP0CLKSEL_Pos)) & CLOCK_PFCSR_CMP0CLKSEL_Msk)
#else
#define CLOCK_PFCSR_ADC0CLKSEL(x)   (((uint32_t)(((uint32_t)(x)) << CLOCK_PFCSR_ADC0CLKSEL_Pos)) & CLOCK_PFCSR_ADC0CLKSEL_Msk)
#define CLOCK_PFCSR_CAN0CLKSEL(x)   (((uint32_t)(((uint32_t)(x)) << CLOCK_PFCSR_CAN0CLKSEL_Pos)) & CLOCK_PFCSR_CAN0CLKSEL_Msk)
#define CLOCK_PFCSR_TIMER0CLKSEL(x) (((uint32_t)(((uint32_t)(x)) << CLOCK_PFCSR_TIMER0CLKSEL_Pos)) & CLOCK_PFCSR_TIMER0CLKSEL_Msk)
#define CLOCK_PFCSR_TIMER1CLKSEL(x) (((uint32_t)(((uint32_t)(x)) << CLOCK_PFCSR_TIMER1CLKSEL_Pos)) & CLOCK_PFCSR_TIMER1CLKSEL_Msk)
#define CLOCK_PFCSR_CMP0CLKSEL(x)   (((uint32_t)(((uint32_t)(x)) << CLOCK_PFCSR_CMP0CLKSEL_Pos)) & CLOCK_PFCSR_CMP0CLKSEL_Msk)
#endif

/*******APIs*******************************************************************/
#if defined(__cplusplus)
extern "C" {
#endif

/*!
 * @brief Set HSI clock enable or not in Stop mode
 *
 * @param[in] regBase: CLOCK register base address
 * @param[in] enable: true: HSI_CLK keep enable in Stop mode
 *                    false: HSI_CLK is diabled by hardware automaticlly in Stop mode
 * @return None
 */
static inline void CLOCK_REG_SetHsiEnableInStop(CLOCK_Type* regBase, bool enable)
{
    uint32_t regValue = regBase->CR;

    regValue &= (~CLOCK_CR_HSISTOPEN_Msk);
    regValue |= CLOCK_CR_HSISTOPEN(enable ? 1U : 0U);
    regBase->CR = regValue;
}

/*!
 * @brief Get HSI clock enable or not in Stop mode
 *
 * @param[in] regBase: CLOCK register base address
 * @return: true: HSI_CLK is enable in Stop mode
 *          false: HSI_CLK is diabled by hardware automaticlly in Stop mode
 */
static inline bool CLOCK_REG_GetHsiEnableInStop(CLOCK_Type* regBase)
{
    uint32_t regValue = regBase->CR;

    regValue = (regValue & CLOCK_CR_HSISTOPEN_Msk) >> CLOCK_CR_HSISTOPEN_Pos;

    return (regValue == 1U) ? true : false;
}

/*!
 * @brief Set system clock source
 *        At least 5us must be wait to assure system clock has been switched successfully
 *
 * @param[in] regBase: CLOCK register base address
 * @param[in] sysClkSrc: System clock source selection value
 * @return None
 */
static inline void CLOCK_REG_SetSystemClockSource(CLOCK_Type* regBase,
                                                  sys_clk_src_t sysClkSrc)
{
    uint32_t regValue = regBase->CR;
    volatile uint32_t readyTime = 1000U;

    regValue &= (~CLOCK_CR_SYSCLKSRC_Msk);
    regValue |= CLOCK_CR_SYSCLKSRC(sysClkSrc);
    regBase->CR = regValue;

    while (readyTime--) {
        __NOP();
    }
}

/*!
 * @brief Set PERI0 prescaler, mainly for CAN clock source
 *
 * @param[in] regBase: CLOCK register base address
 * @param[in] peri0ClkPrescaler: PERI0 prescaler value
 * @return None
 */
static inline void CLOCK_REG_SetPeri0Prescaler(CLOCK_Type* regBase,
                                               peri0_clk_prescaler_t peri0Clkprescaler)
{
    uint32_t regValue = regBase->CR;

    regValue &= (~CLOCK_CR_PERI0PVAL_Msk);
    regValue |= CLOCK_CR_PERI0PVAL(peri0Clkprescaler);
    regBase->CR = regValue;
}

/*!
 * @brief Get PERI0 prescaler
 *
 * @param[in] regBase: CLOCK register base address
 * @return PERI0 prescaler value
 */
static inline uint32_t CLOCK_REG_GetPeri0Prescaler(CLOCK_Type* regBase)
{
    uint32_t regValue = regBase->CR;
    uint32_t retValue = 1U;

    regValue = (regValue & CLOCK_CR_PERI0PVAL_Msk) >> CLOCK_CR_PERI0PVAL_Pos;
    if (regValue == 0U) {
        retValue = 1U;
    } else if (regValue == 1U) {
        retValue = 2U;
    } else if (regValue == 2U) {
        retValue = 4U;
    } else if (regValue == 3U) {
#if (CONFIG_CLOCK_NEW_FEATURES == 1U)
        retValue = 1U;
#else
        retValue = 8U;
#endif
    } else {
        /* Do nothing */
    }

    return retValue;
}

/*!
 * @brief Get PERI0 prescaler by enum
 *
 * @param[in] regBase: CLOCK register base address
 * @return PERI0 prescaler value of enum definition
 */
static inline peri0_clk_prescaler_t CLOCK_REG_GetPeri0PrescalerByEnum(CLOCK_Type* regBase)
{
    uint32_t regValue = regBase->CR;
    peri0_clk_prescaler_t peri0Clkprescaler = PERI0_CLK_PRESCALER_1;

    regValue = (regValue & CLOCK_CR_PERI0PVAL_Msk) >> CLOCK_CR_PERI0PVAL_Pos;
    if (regValue == 0U) {
        peri0Clkprescaler = PERI0_CLK_PRESCALER_1;
    } else if (regValue == 1U) {
        peri0Clkprescaler = PERI0_CLK_PRESCALER_2;
    } else if (regValue == 2U) {
        peri0Clkprescaler = PERI0_CLK_PRESCALER_4;
    } else if (regValue == 3U) {
#if (CONFIG_CLOCK_NEW_FEATURES == 1U)
        peri0Clkprescaler = PERI0_CLK_PRESCALER_1;
#else
        peri0Clkprescaler = PERI0_CLK_PRESCALER_8;
#endif
    } else {
        /* Do nothing */
    }

    return peri0Clkprescaler;
}

/*!
 * @brief Set PERI1 prescaler, mainly for ADC function clock source
 *
 * @param[in] regBase: CLOCK register base address
 * @param[in] peri1ClkPrescaler: PERI1 prescaler value
 * @return None
 */
static inline void CLOCK_REG_SetPeri1Prescaler(CLOCK_Type* regBase,
                                               peri1_clk_prescaler_t peri1Clkprescaler)
{
    uint32_t regValue = regBase->CR;

    regValue &= (~CLOCK_CR_PERI1PVAL_Msk);
    regValue |= CLOCK_CR_PERI1PVAL(peri1Clkprescaler);
    regBase->CR = regValue;
}

/*!
 * @brief Get PERI1 prescaler
 *
 * @param[in] regBase: CLOCK register base address
 * @return PERI1 prescaler value
 */
static inline uint32_t CLOCK_REG_GetPeri1Prescaler(CLOCK_Type* regBase)
{
    uint32_t regValue = regBase->CR;
    uint32_t retValue = 4U;

    regValue = (regValue & CLOCK_CR_PERI1PVAL_Msk) >> CLOCK_CR_PERI1PVAL_Pos;

#if (CONFIG_CLOCK_NEW_FEATURES == 1U)
    if (regValue == 0U) {
        retValue = 4U;
    } else if (regValue == 1U) {
        retValue = 6U;
    } else if (regValue == 2U) {
        retValue = 8U;
    } else if (regValue == 3U) {
        retValue = 10U;
    } else {
        /* Do nothing */
    }
#else
    if (regValue == 0U) {
        retValue = 1U;
    } else if (regValue == 1U) {
        retValue = 2U;
    } else if (regValue == 2U) {
        retValue = 4U;
    } else if (regValue == 3U) {
        retValue = 8U;
    } else {
        /* Do nothing */
    }
#endif

    return retValue;
}

/*!
 * @brief Get PERI1 prescaler by enum
 *
 * @param[in] regBase: CLOCK register base address
 * @return PERI1 prescaler value of enum definition
 */
static inline peri1_clk_prescaler_t CLOCK_REG_GetPeri1PrescalerByEnum(CLOCK_Type* regBase)
{
    uint32_t regValue = regBase->CR;
    peri1_clk_prescaler_t peri1Clkprescaler = PERI1_CLK_PRESCALER_4;

    regValue = (regValue & CLOCK_CR_PERI1PVAL_Msk) >> CLOCK_CR_PERI1PVAL_Pos;

#if (CONFIG_CLOCK_NEW_FEATURES == 1U)
    if (regValue == 0U) {
        peri1Clkprescaler = PERI1_CLK_PRESCALER_4;
    } else if (regValue == 1U) {
        peri1Clkprescaler = PERI1_CLK_PRESCALER_6;
    } else if (regValue == 2U) {
        peri1Clkprescaler = PERI1_CLK_PRESCALER_8;
    } else if (regValue == 3U) {
        peri1Clkprescaler = PERI1_CLK_PRESCALER_10;
    } else {
        /* Do nothing */
    }
#else
    if (regValue == 0U) {
        peri1Clkprescaler = PERI1_CLK_PRESCALER_1;
    } else if (regValue == 1U) {
        peri1Clkprescaler = PERI1_CLK_PRESCALER_2;
    } else if (regValue == 2U) {
        peri1Clkprescaler = PERI1_CLK_PRESCALER_4;
    } else if (regValue == 3U) {
        peri1Clkprescaler = PERI1_CLK_PRESCALER_8;
    } else {
        /* Do nothing */
    }
#endif

    return peri1Clkprescaler;
}

/*!
 * @brief Set AHB prescaler
 *
 * @param[in] regBase: CLOCK register base address
 * @param[in] ahbClkPrescaler: AHB prescaler value
 * @return None
 */
static inline void CLOCK_REG_SetAhbPrescaler(CLOCK_Type* regBase,
                                             ahb_clk_prescaler_t ahbClkPrescaler)
{
    uint32_t regValue = regBase->CR;

    regValue &= (~CLOCK_CR_AHBPVAL_Msk);
    regValue |= CLOCK_CR_AHBPVAL(ahbClkPrescaler);
    regBase->CR = regValue;
}

/*!
 * @brief Get AHB prescaler
 *
 * @param[in] regBase: CLOCK register base address
 * @return AHB prescaler value
 */
static inline uint32_t CLOCK_REG_GetAhbPrescaler(CLOCK_Type* regBase)
{
    uint32_t regValue = regBase->CR;
    uint32_t retValue = 1U;

    regValue = (regValue & CLOCK_CR_AHBPVAL_Msk) >> CLOCK_CR_AHBPVAL_Pos;
    if (regValue == 0U) {
        retValue = 1U;
    } else if (regValue == 1U) {
        retValue = 2U;
    } else if (regValue == 2U) {
        retValue = 4U;
    } else if (regValue == 3U) {
        retValue = 8U;
    } else {
        /* Do nothing */
    }

    return retValue;
}

/*!
 * @brief Get AHB prescaler by enum
 *
 * @param[in] regBase: CLOCK register base address
 * @return AHB prescaler value of enum definition
 */
static inline ahb_clk_prescaler_t CLOCK_REG_GetAhbPrescalerByEnum(CLOCK_Type* regBase)
{
    uint32_t regValue = regBase->CR;
    ahb_clk_prescaler_t ahbClkPrescaler = AHB_CLK_PRESCALER_1;

    regValue = (regValue & CLOCK_CR_AHBPVAL_Msk) >> CLOCK_CR_AHBPVAL_Pos;
    if (regValue == 0U) {
        ahbClkPrescaler = AHB_CLK_PRESCALER_1;
    } else if (regValue == 1U) {
        ahbClkPrescaler = AHB_CLK_PRESCALER_2;
    } else if (regValue == 2U) {
        ahbClkPrescaler = AHB_CLK_PRESCALER_4;
    } else if (regValue == 3U) {
        ahbClkPrescaler = AHB_CLK_PRESCALER_8;
    } else {
        /* Do nothing */
    }

    return ahbClkPrescaler;
}

/*!
 * @brief Set APB prescaler
 *
 * @param[in] regBase: CLOCK register base address
 * @param[in] apbClkPrescaler: APB prescaler value
 * @return None
 */
static inline void CLOCK_REG_SetApbPrescaler(CLOCK_Type* regBase,
                                             apb_clk_prescaler_t apbClkPrescaler)
{
    uint32_t regValue = regBase->CR;

    regValue &= (~CLOCK_CR_APBPVAL_Msk);
    regValue |= CLOCK_CR_APBPVAL(apbClkPrescaler);
    regBase->CR = regValue;
}

/*!
 * @brief Get APB prescaler
 *
 * @param[in] regBase: CLOCK register base address
 * @return APB prescaler value
 */
static inline uint32_t CLOCK_REG_GetApbPrescaler(CLOCK_Type* regBase)
{
    uint32_t regValue = regBase->CR;
    uint32_t retValue = 1U;

    regValue = (regValue & CLOCK_CR_APBPVAL_Msk) >> CLOCK_CR_APBPVAL_Pos;
    if (regValue == 0U) {
        retValue = 1U;
    } else if (regValue == 1U) {
        retValue = 2U;
    } else if (regValue == 2U) {
        retValue = 4U;
    } else if (regValue == 3U) {
        retValue = 1U;
    } else {
        /* Do nothing */
    }

    return retValue;
}

/*!
 * @brief Get APB prescaler by enum
 *
 * @param[in] regBase: CLOCK register base address
 * @return APB prescaler value of enum definition
 */
static inline apb_clk_prescaler_t CLOCK_REG_GetApbPrescalerByEnum(CLOCK_Type* regBase)
{
    uint32_t regValue = regBase->CR;
    apb_clk_prescaler_t apbClkPrescaler = APB_CLK_PRESCALER_1;

    regValue = (regValue & CLOCK_CR_APBPVAL_Msk) >> CLOCK_CR_APBPVAL_Pos;
    if (regValue == 0U) {
        apbClkPrescaler = APB_CLK_PRESCALER_1;
    } else if (regValue == 1U) {
        apbClkPrescaler = APB_CLK_PRESCALER_2;
    } else if (regValue == 2U) {
        apbClkPrescaler = APB_CLK_PRESCALER_4;
    } else if (regValue == 3U) {
        apbClkPrescaler = APB_CLK_PRESCALER_1;
    } else {
        /* Do nothing */
    }

    return apbClkPrescaler;
}

/*!
 * @brief Set the event to be generated by loss of clock
 *
 * @param[in] regBase: CLOCK register base address
 * @param[in] locEvent: Event to be generated
 * @return None
 */
static inline void CLOCK_REG_SetLocEvent(CLOCK_Type* regBase, loc_event_t locEvent)
{
    uint32_t regValue = regBase->CR;

    regValue &= (~CLOCK_CR_LOCFS_Msk);
    regValue |= CLOCK_CR_LOCFS(locEvent);
    regBase->CR = regValue;
}

/*!
 * @brief Get the event type to be generated by loss of clock
 *
 * @param[in] regBase: CLOCK register base address
 * @return: Event to be generated
 */
static inline loc_event_t CLOCK_REG_GetLocEvent(CLOCK_Type* regBase)
{
    uint32_t regValue = regBase->CR;

    regValue = (regValue & CLOCK_CR_LOCFS_Msk) >> CLOCK_CR_LOCFS_Pos;

    return (regValue == 0U) ? LOC_GEN_RESET : LOC_GEN_INT;
}

/*!
 * @brief Set the event to be generated by loss of lock
 *
 * @param[in] regBase: CLOCK register base address
 * @param[in] lolEvent: Event to be generated
 * @return None
 */
static inline void CLOCK_REG_SetLolEvent(CLOCK_Type* regBase, lol_event_t lolEvent)
{
    uint32_t regValue = regBase->CR;

    regValue &= (~CLOCK_CR_LOLFS_Msk);
    regValue |= CLOCK_CR_LOLFS(lolEvent);
    regBase->CR = regValue;
}

/*!
 * @brief Get the event type to be generated by loss of lock
 *
 * @param[in] regBase: CLOCK register base address
 * @return: Event to be generated
 */
static inline lol_event_t CLOCK_REG_GetLolEvent(CLOCK_Type* regBase)
{
    uint32_t regValue = regBase->CR;

    regValue = (regValue & CLOCK_CR_LOLFS_Msk) >> CLOCK_CR_LOLFS_Pos;

    return (regValue == 0U) ? LOL_GEN_RESET : LOL_GEN_INT;
}

/*!
 * @brief Enable or disable HSE_CLK (output of XOSC circuit)
 *
 * @param[in] regBase: CLOCK register base address
 * @param[in] enable: true: Enable HSE_CLK
 *                    false: Disable HSE_CLK
 * @return None
 */
static inline void CLOCK_REG_SetHseEnable(CLOCK_Type* regBase, bool enable)
{
    uint32_t regValue = regBase->XOSCCR;

    regValue &= (~CLOCK_XOSCCR_EN_Msk);
    regValue |= CLOCK_XOSCCR_EN(enable ? 1U : 0U);
    regBase->XOSCCR = regValue;
}

/*!
 * @brief Get HSE_CLK enable bit
 *
 * @param[in] regBase: CLOCK register base address
 * @return true: HSE_CLK is enabled
 *         false: HSE_CLK is disabled
 */
static inline bool CLOCK_REG_GetHseEnable(CLOCK_Type* regBase)
{
    uint32_t regValue = regBase->XOSCCR;

    regValue = (regValue & CLOCK_XOSCCR_EN_Msk) >> CLOCK_XOSCCR_EN_Pos;

    return (regValue == 1U) ? true : false;
}

/*!
 * @brief Enable or disable XOSC bypass mode
 *
 * @param[in] regBase: CLOCK register base address
 * @param[in] enable: true: Enable XOSC bypass mode
 *                    false: Disable XOSC bypass mode
 * @return None
 */
static inline void CLOCK_REG_SetXoscBypassEnable(CLOCK_Type* regBase, bool enable)
{
    uint32_t regValue = regBase->XOSCCR;

    regValue &= (~CLOCK_XOSCCR_BYPEN_Msk);
    regValue |= CLOCK_XOSCCR_BYPEN(enable ? 1U : 0U);
    regBase->XOSCCR = regValue;
}

/*!
 * @brief Set XOSC current
 *
 * @param[in] regBase: CLOCK register base address
 * @param[in] current: 0: 500uA, 1: 1mA, other values are invalid
 * @return None
 */
static inline void CLOCK_REG_SetXoscIbs(CLOCK_Type* regBase, uint8_t current)
{
    uint32_t regValue = regBase->XOSCCR;

    regValue &= (~CLOCK_XOSCCR_IBS_Msk);
    regValue |= CLOCK_XOSCCR_IBS((current > 1U) ? 1U : current);
    regBase->XOSCCR = regValue;
}

/*!
 * @brief Enable or disable HSE_CLK monitor
 *
 * @param[in] regBase: CLOCK register base address
 * @param[in] enable: true: Enable HSE_CLK monitor
 *                    false: Disable HSE_CLK monitor
 * @return None
 */
static inline void CLOCK_REG_SetHseMonEnable(CLOCK_Type* regBase, bool enable)
{
    uint32_t regValue = regBase->XOSCCR;

    regValue &= (~CLOCK_XOSCCR_MONEN_Msk);
    regValue |= CLOCK_XOSCCR_MONEN(enable ? 1U : 0U);
    regBase->XOSCCR = regValue;
}

/*!
 * @brief Get HSE monitor enable bit
 *
 * @param[in] regBase: CLOCK register base address
 * @return true: HSE monitor is enabled
 *         false: HSE monitor is disabled
 */
static inline bool CLOCK_REG_GetHseMonEnable(CLOCK_Type* regBase)
{
    uint32_t regValue = regBase->XOSCCR;

    regValue = (regValue & CLOCK_XOSCCR_MONEN_Msk) >> CLOCK_XOSCCR_MONEN_Pos;

    return (regValue == 1U) ? true : false;
}

/*!
 * @brief Set Flash Clock
 *
 * @param[in] flashClock: flash Clock
 * @return None
 */
static inline void CLOCK_REG_SetFlashClock(uint32_t flashClock)
{
    uint32_t regValue = FLASH->CFGR;

    regValue &= (~FLASH_CFGR_FREQ_Msk);
    regValue |= (flashClock << FLASH_CFGR_FREQ_Pos);
    FLASH->CFGR = regValue;
}

/*!
 * @brief Set PLL Charge Pump Current
 *
 * @param[in] regBase: CLOCK register base address
 * @param[in] icpValue: ICP value, valid range 0x0 ~ 0xF, current is (icpValue * 4) uA
 * @return None
 */
static inline void CLOCK_REG_SetPllIcp(CLOCK_Type* regBase, uint8_t icpValue)
{
    uint32_t regValue = regBase->PLLCR;

    regValue &= (~CLOCK_PLLCR_ICP_Msk);
    regValue |= CLOCK_PLLCR_ICP((icpValue > 0xFU) ? 0xFU : icpValue);
    regBase->PLLCR = regValue;
}

/*!
 * @brief Enable or disable PLL
 *
 * @param[in] regBase: CLOCK register base address
 * @param[in] enable: true: Enable PLL
 *                    false: Disable PLL
 * @return None
 */
static inline void CLOCK_REG_SetPllEnable(CLOCK_Type* regBase, bool enable)
{
    uint32_t regValue = regBase->PLLCR;

    regValue &= (~CLOCK_PLLCR_EN_Msk);
    regValue |= CLOCK_PLLCR_EN(enable ? 1U : 0U);
    regBase->PLLCR = regValue;
}

/*!
 * @brief Get PLL enable bit
 *
 * @param[in] regBase: CLOCK register base address
 * @return true: PLL is enabled
 *         false: PLL is disabled
 */
static inline bool CLOCK_REG_GetPllEnable(CLOCK_Type* regBase)
{
    uint32_t regValue = regBase->PLLCR;

    regValue = (regValue & CLOCK_PLLCR_EN_Msk) >> CLOCK_PLLCR_EN_Pos;

    return (regValue == 1U) ? true : false;
}

/*!
 * @brief Enable or disable PLL lock monitor
 *
 * @param[in] regBase: CLOCK register base address
 * @param[in] enable: true: Enable monitor
 *                    false: Disable monitor
 * @return None
 */
static inline void CLOCK_REG_SetPllLockMonitorEnable(CLOCK_Type* regBase, bool enable)
{
    uint32_t regValue = regBase->PLLCR;

    regValue &= (~CLOCK_PLLCR_LOCKMONEN_Msk);
    regValue |= CLOCK_PLLCR_LOCKMONEN(enable ? 1U : 0U);
    regBase->PLLCR = regValue;
}

/*!
 * @brief Get PLL lock monitor enable bit
 *
 * @param[in] regBase: CLOCK register base address
 * @return true: PLL lock monitor is enabled
 *         false: PLL lock monitor is disabled
 */
static inline bool CLOCK_REG_GetPllLockMonitorEnable(CLOCK_Type* regBase)
{
    uint32_t regValue = regBase->PLLCR;

    regValue = (regValue & CLOCK_PLLCR_LOCKMONEN_Msk) >> CLOCK_PLLCR_LOCKMONEN_Pos;

    return (regValue == 1U) ? true : false;
}

#if (CONFIG_CLOCK_NEW_FEATURES == 1U)
/*!
 * @brief Enable or disable PLL lock circuit
 *
 * @param[in] regBase: CLOCK register base address
 * @param[in] enable: true: Enable
 *                    false: Disable
 * @return None
 */
static inline void CLOCK_REG_SetPllLockEnable(CLOCK_Type* regBase, bool enable)
{
    uint32_t regValue = regBase->PLLCR;

    regValue &= (~CLOCK_PLLCR_LOCKEN_Msk);
    regValue |= CLOCK_PLLCR_LOCKEN(enable ? 1U : 0U);
    regBase->PLLCR = regValue;
}
#endif

/*!
 * @brief Set PLL reference clock
 *
 * @param[in] regBase: CLOCK register base address
 * @param[in] pllRefClkSrc: PLL reference clock type
 * @return None
 */
static inline void CLOCK_REG_SetPllRefClk(CLOCK_Type* regBase, pll_ref_clk_src_t pllRefClkSrc)
{
    uint32_t regValue = regBase->PLLCR;

    regValue &= (~CLOCK_PLLCR_REFSEL_Msk);
    regValue |= CLOCK_PLLCR_REFSEL(pllRefClkSrc);
    regBase->PLLCR = regValue;
}

/*!
 * @brief Get PLL reference clock
 *
 * @param[in] regBase: CLOCK register base address
 * @return PLL reference clock type
 */
static inline pll_ref_clk_src_t CLOCK_REG_GetPllRefClk(CLOCK_Type* regBase)
{
    uint32_t regValue = regBase->PLLCR;

    regValue = (regValue & CLOCK_PLLCR_REFSEL_Msk) >> CLOCK_PLLCR_REFSEL_Pos;

    return (regValue == 0U) ? PLL_REF_CLK_SRC_HSI : PLL_REF_CLK_SRC_HSE;
}

/*!
 * @brief Set PLL previous divider
 *
 * @param[in] regBase: CLOCK register base address
 * @param[in] preDiv: Previous divider value
 * @return None
 */
static inline void CLOCK_REG_SetPllPreDiv(CLOCK_Type* regBase, uint16_t preDiv)
{
    uint32_t regValue = regBase->PLLCR;

    regValue &= (~CLOCK_PLLCR_PREDIV_Msk);
    regValue |= CLOCK_PLLCR_PREDIV(preDiv);
    regBase->PLLCR = regValue;
}

/*!
 * @brief Get PLL previous divider
 *
 * @param[in] regBase: CLOCK register base address
 * @return PLL previous divider
 */
static inline uint32_t CLOCK_REG_GetPllPreDiv(CLOCK_Type* regBase)
{
    uint32_t regValue = regBase->PLLCR;

    regValue = (regValue & CLOCK_PLLCR_PREDIV_Msk) >> CLOCK_PLLCR_PREDIV_Pos;

    return regValue;
}

/*!
 * @brief Set PLL post divider1
 *
 * @param[in] regBase: CLOCK register base address
 * @param[in] preDiv: Post divider1 value
 * @return None
 */
static inline void CLOCK_REG_SetPllPostDiv1(CLOCK_Type* regBase, uint16_t postDiv1)
{
    uint32_t regValue = regBase->PLLCR;

    regValue &= (~CLOCK_PLLCR_POSTDIV1_Msk);
    regValue |= CLOCK_PLLCR_POSTDIV1(postDiv1);
    regBase->PLLCR = regValue;
}

/*!
 * @brief Get PLL post divider1
 *
 * @param[in] regBase: CLOCK register base address
 * @return PLL post divider1
 */
static inline uint32_t CLOCK_REG_GetPllPostDiv1(CLOCK_Type* regBase)
{
    uint32_t regValue = regBase->PLLCR;

    regValue = (regValue & CLOCK_PLLCR_POSTDIV1_Msk) >> CLOCK_PLLCR_POSTDIV1_Pos;

    return regValue;
}

/*!
 * @brief Set PLL post divider2
 *
 * @param[in] regBase: CLOCK register base address
 * @param[in] preDiv: Post divider2 value
 * @return None
 */
static inline void CLOCK_REG_SetPllPostDiv2(CLOCK_Type* regBase, uint16_t postDiv2)
{
    uint32_t regValue = regBase->PLLCR;

    regValue &= (~CLOCK_PLLCR_POSTDIV2_Msk);
    regValue |= CLOCK_PLLCR_POSTDIV2(postDiv2);
    regBase->PLLCR = regValue;
}

/*!
 * @brief Get PLL post divider2
 *
 * @param[in] regBase: CLOCK register base address
 * @return PLL post divider2
 */
static inline uint32_t CLOCK_REG_GetPllPostDiv2(CLOCK_Type* regBase)
{
    uint32_t regValue = regBase->PLLCR;

    regValue = (regValue & CLOCK_PLLCR_POSTDIV2_Msk) >> CLOCK_PLLCR_POSTDIV2_Pos;

    return regValue;
}

/*!
 * @brief Set PLL feedback divider
 *
 * @param[in] regBase: CLOCK register base address
 * @param[in] preDiv: Feedback divider value
 * @return None
 */
static inline void CLOCK_REG_SetPllFbDiv(CLOCK_Type* regBase, uint16_t fbDiv)
{
    uint32_t regValue = regBase->PLLCR;

    regValue &= (~CLOCK_PLLCR_FBDIV_Msk);
    regValue |= CLOCK_PLLCR_FBDIV(fbDiv);
    regBase->PLLCR = regValue;
}

/*!
 * @brief Get PLL feedback divider
 *
 * @param[in] regBase: CLOCK register base address
 * @return PLL feedback divider
 */
static inline uint32_t CLOCK_REG_GetPllFbDiv(CLOCK_Type* regBase)
{
    uint32_t regValue = regBase->PLLCR;

    regValue = (regValue & CLOCK_PLLCR_FBDIV_Msk) >> CLOCK_PLLCR_FBDIV_Pos;

    return regValue;
}

/*!
 * @brief Set PLL VCO divider
 *
 * @param[in] regBase: CLOCK register base address
 * @param[in] vcoDiv: VCO divider value
 * @return None
 */
static inline void CLOCK_REG_SetPllVcoDiv(CLOCK_Type* regBase, uint16_t vcoDiv)
{
    uint32_t regValue = 0U;

    *(volatile uint32_t*)(0x4000000CUL) = 0xB2063001UL;
    regValue = *(volatile uint32_t*)(0x40002038UL);

    regValue &= (~0x58UL);
    if (vcoDiv == 1U) {
        regValue |= 0x40UL;
    }

    /* Lock range: 2b'01 */
    regValue |= 0x8UL;

    *(volatile uint32_t*)(0x40002038UL) = regValue;
    *(volatile uint32_t*)(0x4000000CUL) = 0xB2063000UL;
}

/*!
 * @brief Check if PLL_CLK is loss of lock
 *
 * @param[in] regBase: CLOCK register base address
 * @return true: PLL_CLK is unlocked
 *         false: PLL_CLK is locked
 */
static inline bool CLOCK_REG_PllIsLoss(CLOCK_Type* regBase)
{
    uint32_t regValue = regBase->SR;

    regValue = (regValue & CLOCK_SR_LOLF_Msk) >> CLOCK_SR_LOLF_Pos;

    return (regValue == 1U) ? true : false;
}

/*!
 * @brief Clear PLL loss of lock flag
 *
 * @param[in] regBase: CLOCK register base address
 * @return None
 */
static inline void CLOCK_REG_ClearLolFlag(CLOCK_Type* regBase)
{
    regBase->SR = CLOCK_SR_LOLF_Msk;
}

/*!
 * @brief Check if HSE_CLK is loss of clock
 *
 * @param[in] regBase: CLOCK register base address
 * @return true: HSE_CLK is loss of clock
 *         false: HSE_CLK is ok
 */
static inline bool CLOCK_REG_HseIsLoss(CLOCK_Type* regBase)
{
    uint32_t regValue = regBase->SR;

    regValue = (regValue & CLOCK_SR_LOCF_Msk) >> CLOCK_SR_LOCF_Pos;

    return (regValue == 1U) ? true : false;
}

/*!
 * @brief Clear HSE loss of clock flag
 *
 * @param[in] regBase: CLOCK register base address
 * @return None
 */
static inline void CLOCK_REG_ClearLocFlag(CLOCK_Type* regBase)
{
    regBase->SR = CLOCK_SR_LOCF_Msk;
}

/*!
 * @brief Check if PLL_CLK is ready
 *
 * @param[in] regBase: CLOCK register base address
 * @return true: PLL_CLK is ready
 *         false: PLL_CLK is not ready
 */
static inline bool CLOCK_REG_PllIsReady(CLOCK_Type* regBase)
{
    uint32_t regValue = regBase->SR;

    regValue = (regValue & CLOCK_SR_PLLRDYF_Msk) >> CLOCK_SR_PLLRDYF_Pos;

    return (regValue == 1U) ? true : false;
}

/*!
 * @brief Check if HSE_CLK is ready
 *
 * @param[in] regBase: CLOCK register base address
 * @return true: HSE_CLK is ready
 *         false: HSE_CLK is not ready
 */
static inline bool CLOCK_REG_HseIsReady(CLOCK_Type* regBase)
{
    uint32_t regValue = regBase->SR;

    regValue = (regValue & CLOCK_SR_HSERDYF_Msk) >> CLOCK_SR_HSERDYF_Pos;

    return (regValue == 1U) ? true : false;
}

/*!
 * @brief Get system clock source
 *
 * @param[in] regBase: CLOCK register base address
 * @return System clock source
 */
static inline sys_clk_src_t CLOCK_REG_GetSystemClockSource(CLOCK_Type* regBase)
{
    uint32_t regValue = regBase->CR;
    sys_clk_src_t retValue = SYS_CLK_SRC_HSI;

    regValue = (regValue & CLOCK_CR_SYSCLKSRC_Msk) >> CLOCK_CR_SYSCLKSRC_Pos;
    if (regValue == 0U) {
        retValue = SYS_CLK_SRC_HSI;
    } else if (regValue == 1U) {
        retValue = SYS_CLK_SRC_HSE;
    } else if (regValue == 2U) {
        retValue = SYS_CLK_SRC_PLL;
    } else if (regValue == 3U) {
        retValue = SYS_CLK_SRC_HSI;
    } else {
        /* Do nothing */
    }

    return retValue;
}

/*!
 * @brief Set AHB module bus clock enable or not
 *
 * @param[in] regBase: CLOCK register base address
 * @param[in] ahbModuleClkGate: APB module bus clock gatings
 * @return None
 */
static inline void CLOCK_REG_SetAhbModuleBusClockEnable(CLOCK_Type* regBase,
                                                        uint32_t ahbModuleClkGate)
{
    regBase->AHBPCCR = ahbModuleClkGate;
}

/*!
 * @brief Get current AHB module bus clock gate status
 *
 * @param[in] regBase: CLOCK register base address
 * @return Current AHB module bus clock gate status
 */
static inline uint32_t CLOCK_REG_GetAhbModuleBusClock(CLOCK_Type* regBase)
{
    return regBase->AHBPCCR;
}

/*!
 * @brief Set APB module bus clock enable or not
 *
 * @param[in] regBase: CLOCK register base address
 * @param[in] apbModuleClkGate: APB module bus clock gatings
 * @return None
 */
static inline void CLOCK_REG_SetApbModuleBusClockEnable(CLOCK_Type* regBase,
                                                        uint32_t apbModuleClkGate)
{
    regBase->APBPCCR = apbModuleClkGate;
}

/*!
 * @brief Get current APB module bus clock gate status
 *
 * @param[in] regBase: CLOCK register base address
 * @return Current APB module bus clock gate status
 */
static inline uint32_t CLOCK_REG_GetApbModuleBusClock(CLOCK_Type* regBase)
{
    return regBase->APBPCCR;
}

/*!
 * @brief Set AHB module soft reset
 *
 * @param[in] regBase: CLOCK register base address
 * @param[in] ahbModuleSoftReset: AHB module soft reset settings
 * @return None
 */
static inline void CLOCK_REG_SetAhbModuleSoftReset(CLOCK_Type* regBase,
                                                   uint32_t ahbModuleSoftReset)
{
    regBase->AHBPSRR = ahbModuleSoftReset;
}

/*!
 * @brief Get current AHB module soft reset status
 *
 * @param[in] regBase: CLOCK register base address
 * @return Current AHB module soft reset status
 */
static inline uint32_t CLOCK_REG_GetAhbModuleSoftReset(CLOCK_Type* regBase)
{
    return regBase->AHBPSRR;
}

/*!
 * @brief Set APB module soft reset
 *
 * @param[in] regBase: CLOCK register base address
 * @param[in] apbModuleSoftReset: APB module soft reset settings
 * @return None
 */
static inline void CLOCK_REG_SetApbModuleSoftReset(CLOCK_Type* regBase,
                                                   uint32_t apbModuleSoftReset)
{
    regBase->APBPSRR = apbModuleSoftReset;
}

/*!
 * @brief Get current APB module soft reset status
 *
 * @param[in] regBase: CLOCK register base address
 * @return Current APB module soft reset status
 */
static inline uint32_t CLOCK_REG_GetApbModuleSoftReset(CLOCK_Type* regBase)
{
    return regBase->APBPSRR;
}

/*!
 * @brief Set ADC0 clock source
 *
 * @param[in] regBase: CLOCK register base address
 * @param[in] adcClkSrc: ADC clock source selection value
 * @return None
 */
static inline void CLOCK_REG_SetAdc0ClockSource(CLOCK_Type* regBase, adc_clk_src_t adcClkSrc)
{
    uint32_t regValue = regBase->PFCSR;

    regValue &= (~CLOCK_PFCSR_ADC0CLKSEL_Msk);
    regValue |= CLOCK_PFCSR_ADC0CLKSEL(adcClkSrc);
    regBase->PFCSR = regValue;
}

/*!
 * @brief Get ADC0 clock source
 *
 * @param[in] regBase: CLOCK register base address
 * @return ADC0 clock source
 */
static inline adc_clk_src_t CLOCK_REG_GetAdc0ClockSource(CLOCK_Type* regBase)
{
    uint32_t regValue = regBase->PFCSR;
    adc_clk_src_t retValue = ADC_CLK_SRC_OFF;

    regValue = (regValue & CLOCK_PFCSR_ADC0CLKSEL_Msk) >> CLOCK_PFCSR_ADC0CLKSEL_Pos;
    if (regValue == 0U) {
        retValue = ADC_CLK_SRC_OFF;
    } else if (regValue == 1U) {
        retValue = ADC_CLK_SRC_PERI1;
    } else if (regValue == 2U) {
        retValue = ADC_CLK_SRC_HSI;
    } else if (regValue == 3U) {
        retValue = ADC_CLK_SRC_HSE;
    } else {
        /* Do nothing */
    }

    return retValue;
}

#if (CONFIG_CLOCK_NEW_FEATURES == 1U)
/*!
 * @brief Set ADC1 clock source
 *
 * @param[in] regBase: CLOCK register base address
 * @param[in] adcClkSrc: ADC clock source selection value
 * @return None
 */
static inline void CLOCK_REG_SetAdc1ClockSource(CLOCK_Type* regBase, adc_clk_src_t adcClkSrc)
{
    uint32_t regValue = regBase->PFCSR;

    regValue &= (~CLOCK_PFCSR_ADC1CLKSEL_Msk);
    regValue |= CLOCK_PFCSR_ADC1CLKSEL(adcClkSrc);
    regBase->PFCSR = regValue;
}

/*!
 * @brief Get ADC1 clock source
 *
 * @param[in] regBase: CLOCK register base address
 * @return ADC1 clock source
 */
static inline adc_clk_src_t CLOCK_REG_GetAdc1ClockSource(CLOCK_Type* regBase)
{
    uint32_t regValue = regBase->PFCSR;
    adc_clk_src_t retValue = ADC_CLK_SRC_OFF;

    regValue = (regValue & CLOCK_PFCSR_ADC1CLKSEL_Msk) >> CLOCK_PFCSR_ADC1CLKSEL_Pos;
    if (regValue == 0U) {
        retValue = ADC_CLK_SRC_OFF;
    } else if (regValue == 1U) {
        retValue = ADC_CLK_SRC_PERI1;
    } else if (regValue == 2U) {
        retValue = ADC_CLK_SRC_HSI;
    } else if (regValue == 3U) {
        retValue = ADC_CLK_SRC_HSE;
    } else {
        /* Do nothing */
    }

    return retValue;
}
#endif

/*!
 * @brief Set CAN0 clock source
 *
 * @param[in] regBase: CLOCK register base address
 * @param[in] canClkSrc: CAN clock source selection value
 * @return None
 */
static inline void CLOCK_REG_SetCan0ClockSource(CLOCK_Type* regBase, can_clk_src_t canClkSrc)
{
    uint32_t regValue = regBase->PFCSR;

    regValue &= (~CLOCK_PFCSR_CAN0CLKSEL_Msk);
    regValue |= CLOCK_PFCSR_CAN0CLKSEL(canClkSrc);
    regBase->PFCSR = regValue;
}

/*!
 * @brief Get CAN0 clock source
 *
 * @param[in] regBase: CLOCK register base address
 * @return CAN0 clock source
 */
static inline can_clk_src_t CLOCK_REG_GetCan0ClockSource(CLOCK_Type* regBase)
{
    uint32_t regValue = regBase->PFCSR;
    can_clk_src_t retValue = CAN_CLK_SRC_OFF;

    regValue = (regValue & CLOCK_PFCSR_CAN0CLKSEL_Msk) >> CLOCK_PFCSR_CAN0CLKSEL_Pos;
    if (regValue == 0U) {
        retValue = CAN_CLK_SRC_OFF;
    } else if (regValue == 1U) {
        retValue = CAN_CLK_SRC_HSE;
    } else if (regValue == 2U) {
#if (CONFIG_CLOCK_NEW_FEATURES == 1U)
        retValue = CAN_CLK_SRC_APB;
#else
        retValue = CAN_CLK_SRC_PERI0;
#endif
    } else {
        retValue = CAN_CLK_SRC_OFF;
    }

    return retValue;
}

#if (CONFIG_CLOCK_NEW_FEATURES == 1U)
/*!
 * @brief Set CAN1 clock source
 *
 * @param[in] regBase: CLOCK register base address
 * @param[in] canClkSrc: CAN clock source selection value
 * @return None
 */
static inline void CLOCK_REG_SetCan1ClockSource(CLOCK_Type* regBase, can_clk_src_t canClkSrc)
{
    uint32_t regValue = regBase->PFCSR;

    regValue &= (~CLOCK_PFCSR_CAN1CLKSEL_Msk);
    regValue |= CLOCK_PFCSR_CAN1CLKSEL(canClkSrc);
    regBase->PFCSR = regValue;
}

/*!
 * @brief Get CAN1 clock source
 *
 * @param[in] regBase: CLOCK register base address
 * @return CAN1 clock source
 */
static inline can_clk_src_t CLOCK_REG_GetCan1ClockSource(CLOCK_Type* regBase)
{
    uint32_t regValue = regBase->PFCSR;
    can_clk_src_t retValue = CAN_CLK_SRC_OFF;

    regValue = (regValue & CLOCK_PFCSR_CAN1CLKSEL_Msk) >> CLOCK_PFCSR_CAN1CLKSEL_Pos;
    if (regValue == 0U) {
        retValue = CAN_CLK_SRC_OFF;
    } else if (regValue == 1U) {
        retValue = CAN_CLK_SRC_HSE;
    } else if (regValue == 2U) {
        retValue = CAN_CLK_SRC_APB;
    } else {
        retValue = CAN_CLK_SRC_OFF;
    }

    return retValue;
}

/*!
 * @brief Set CAN2 clock source
 *
 * @param[in] regBase: CLOCK register base address
 * @param[in] canClkSrc: CAN clock source selection value
 * @return None
 */
static inline void CLOCK_REG_SetCan2ClockSource(CLOCK_Type* regBase, can_clk_src_t canClkSrc)
{
    uint32_t regValue = regBase->PFCSR;

    regValue &= (~CLOCK_PFCSR_CAN2CLKSEL_Msk);
    regValue |= CLOCK_PFCSR_CAN2CLKSEL(canClkSrc);
    regBase->PFCSR = regValue;
}

/*!
 * @brief Get CAN2 clock source
 *
 * @param[in] regBase: CLOCK register base address
 * @return CAN2 clock source
 */
static inline can_clk_src_t CLOCK_REG_GetCan2ClockSource(CLOCK_Type* regBase)
{
    uint32_t regValue = regBase->PFCSR;
    can_clk_src_t retValue = CAN_CLK_SRC_OFF;

    regValue = (regValue & CLOCK_PFCSR_CAN2CLKSEL_Msk) >> CLOCK_PFCSR_CAN2CLKSEL_Pos;
    if (regValue == 0U) {
        retValue = CAN_CLK_SRC_OFF;
    } else if (regValue == 1U) {
        retValue = CAN_CLK_SRC_HSE;
    } else if (regValue == 2U) {
        retValue = CAN_CLK_SRC_APB;
    } else {
        retValue = CAN_CLK_SRC_OFF;
    }

    return retValue;
}
#endif

/*!
 * @brief Set Timer0 clock source
 *
 * @param[in] regBase: CLOCK register base address
 * @param[in] timerClkSrc: Timer clock source selection value
 * @return None
 */
static inline void CLOCK_REG_SetTimer0ClockSource(CLOCK_Type* regBase, timer_clk_src_t timerClkSrc)
{
    uint32_t regValue = regBase->PFCSR;

    regValue &= (~CLOCK_PFCSR_TIMER0CLKSEL_Msk);
    regValue |= CLOCK_PFCSR_TIMER0CLKSEL(timerClkSrc);
    regBase->PFCSR = regValue;
}

/*!
 * @brief Get Timer0 clock source
 *
 * @param[in] regBase: CLOCK register base address
 * @return Timer0 clock source
 */
static inline timer_clk_src_t CLOCK_REG_GetTimer0ClockSource(CLOCK_Type* regBase)
{
    uint32_t regValue = regBase->PFCSR;
    timer_clk_src_t retValue = TIMER_CLK_SRC_OFF;

    regValue = (regValue & CLOCK_PFCSR_TIMER0CLKSEL_Msk) >> CLOCK_PFCSR_TIMER0CLKSEL_Pos;
    if (regValue == 0U) {
        retValue = TIMER_CLK_SRC_OFF;
    } else if (regValue == 1U) {
        retValue = TIMER_CLK_SRC_TIMERIN;
    } else if (regValue == 2U) {
#if (CONFIG_CLOCK_NEW_FEATURES == 1U)
        retValue = TIMER_CLK_SRC_PERI0;
#else
        retValue = TIMER_CLK_SRC_APB;
#endif
    } else if (regValue == 3U) {
        retValue = TIMER_CLK_SRC_LSI;
    } else {
        /* Do nothing */
    }

    return retValue;
}

/*!
 * @brief Set Timer1 clock source
 *
 * @param[in] regBase: CLOCK register base address
 * @param[in] timerClkSrc: Timer clock source selection value
 * @return None
 */
static inline void CLOCK_REG_SetTimer1ClockSource(CLOCK_Type* regBase, timer_clk_src_t timerClkSrc)
{
    uint32_t regValue = regBase->PFCSR;

    regValue &= (~CLOCK_PFCSR_TIMER1CLKSEL_Msk);
    regValue |= CLOCK_PFCSR_TIMER1CLKSEL(timerClkSrc);
    regBase->PFCSR = regValue;
}

/*!
 * @brief Get Timer1 clock source
 *
 * @param[in] regBase: CLOCK register base address
 * @return Timer1 clock source
 */
static inline timer_clk_src_t CLOCK_REG_GetTimer1ClockSource(CLOCK_Type* regBase)
{
    uint32_t regValue = regBase->PFCSR;
    timer_clk_src_t retValue = TIMER_CLK_SRC_OFF;

    regValue = (regValue & CLOCK_PFCSR_TIMER1CLKSEL_Msk) >> CLOCK_PFCSR_TIMER1CLKSEL_Pos;
    if (regValue == 0U) {
        retValue = TIMER_CLK_SRC_OFF;
    } else if (regValue == 1U) {
        retValue = TIMER_CLK_SRC_TIMERIN;
    } else if (regValue == 2U) {
#if (CONFIG_CLOCK_NEW_FEATURES == 1U)
        retValue = TIMER_CLK_SRC_PERI0;
#else
        retValue = TIMER_CLK_SRC_APB;
#endif
    } else if (regValue == 3U) {
        retValue = TIMER_CLK_SRC_LSI;
    } else {
        /* Do nothing */
    }

    return retValue;
}

#if (CONFIG_CLOCK_NEW_FEATURES == 1U)
/*!
 * @brief Set Timer2 clock source
 *
 * @param[in] regBase: CLOCK register base address
 * @param[in] timerClkSrc: Timer clock source selection value
 * @return None
 */
static inline void CLOCK_REG_SetTimer2ClockSource(CLOCK_Type* regBase, timer_clk_src_t timerClkSrc)
{
    uint32_t regValue = regBase->PFCSR;

    regValue &= (~CLOCK_PFCSR_TIMER2CLKSEL_Msk);
    regValue |= CLOCK_PFCSR_TIMER2CLKSEL(timerClkSrc);
    regBase->PFCSR = regValue;
}

/*!
 * @brief Get Timer2 clock source
 *
 * @param[in] regBase: CLOCK register base address
 * @return Timer2 clock source
 */
static inline timer_clk_src_t CLOCK_REG_GetTimer2ClockSource(CLOCK_Type* regBase)
{
    uint32_t regValue = regBase->PFCSR;
    timer_clk_src_t retValue = TIMER_CLK_SRC_OFF;

    regValue = (regValue & CLOCK_PFCSR_TIMER2CLKSEL_Msk) >> CLOCK_PFCSR_TIMER2CLKSEL_Pos;
    if (regValue == 0U) {
        retValue = TIMER_CLK_SRC_OFF;
    } else if (regValue == 1U) {
        retValue = TIMER_CLK_SRC_TIMERIN;
    } else if (regValue == 2U) {
        retValue = TIMER_CLK_SRC_PERI0;
    } else if (regValue == 3U) {
        retValue = TIMER_CLK_SRC_LSI;
    } else {
        /* Do nothing */
    }

    return retValue;
}

/*!
 * @brief Set Timer3 clock source
 *
 * @param[in] regBase: CLOCK register base address
 * @param[in] timerClkSrc: Timer clock source selection value
 * @return None
 */
static inline void CLOCK_REG_SetTimer3ClockSource(CLOCK_Type* regBase, timer_clk_src_t timerClkSrc)
{
    uint32_t regValue = regBase->PFCSR;

    regValue &= (~CLOCK_PFCSR_TIMER3CLKSEL_Msk);
    regValue |= CLOCK_PFCSR_TIMER3CLKSEL(timerClkSrc);
    regBase->PFCSR = regValue;
}

/*!
 * @brief Get Timer3 clock source
 *
 * @param[in] regBase: CLOCK register base address
 * @return Timer3 clock source
 */
static inline timer_clk_src_t CLOCK_REG_GetTimer3ClockSource(CLOCK_Type* regBase)
{
    uint32_t regValue = regBase->PFCSR;
    timer_clk_src_t retValue = TIMER_CLK_SRC_OFF;

    regValue = (regValue & CLOCK_PFCSR_TIMER3CLKSEL_Msk) >> CLOCK_PFCSR_TIMER3CLKSEL_Pos;
    if (regValue == 0U) {
        retValue = TIMER_CLK_SRC_OFF;
    } else if (regValue == 1U) {
        retValue = TIMER_CLK_SRC_TIMERIN;
    } else if (regValue == 2U) {
        retValue = TIMER_CLK_SRC_PERI0;
    } else if (regValue == 3U) {
        retValue = TIMER_CLK_SRC_LSI;
    } else {
        /* Do nothing */
    }

    return retValue;
}
#endif

/*!
 * @brief Set CMP0 clock source
 *
 * @param[in] regBase: CLOCK register base address
 * @param[in] cmpClkSrc: CMP clock source selection value
 * @return None
 */
static inline void CLOCK_REG_SetCmp0ClockSource(CLOCK_Type* regBase, cmp_clk_src_t cmpClkSrc)
{
    uint32_t regValue = regBase->PFCSR;

    regValue &= (~CLOCK_PFCSR_CMP0CLKSEL_Msk);
    regValue |= CLOCK_PFCSR_CMP0CLKSEL(cmpClkSrc);
    regBase->PFCSR = regValue;
}

/*!
 * @brief Get CMP0 clock source
 *
 * @param[in] regBase: CLOCK register base address
 * @return CMP0 clock source
 */
static inline cmp_clk_src_t CLOCK_REG_GetCmp0ClockSource(CLOCK_Type* regBase)
{
    uint32_t regValue = regBase->PFCSR;
    cmp_clk_src_t retValue = CMP_CLK_SRC_OFF;

    regValue = (regValue & CLOCK_PFCSR_CMP0CLKSEL_Msk) >> CLOCK_PFCSR_CMP0CLKSEL_Pos;
    if (regValue == 0U) {
        retValue = CMP_CLK_SRC_OFF;
    } else if (regValue == 1U) {
#if (CONFIG_CLOCK_NEW_FEATURES == 1U)
        retValue = CMP_CLK_SRC_PERI0;
#else
        retValue = CMP_CLK_SRC_APB;
#endif
    } else if (regValue == 2U) {
        retValue = CMP_CLK_SRC_LSI;
    } else {
        retValue = CMP_CLK_SRC_OFF;
    }

    return retValue;
}

#if defined(__cplusplus)
}
#endif

#endif /* CLOCK_REG_ACCESS_H */

/*******EOF********************************************************************/

